//@author A0086393U
package rightnow.ui.widgets;

import java.net.URL;

import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
import org.joda.time.Days;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import rightnow.storage.Task;
import rightnow.ui.MainApp;
import rightnow.util.DateTimeFormatters;
import rightnow.util.UiOptions;
import rightnow.util.UiUtils;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;

/**
 * FX-Controller for the TaskView.fxml display element.
 * Contains UI logic for managing what to display in the Task View.
 * Not heavily logged because this is created a large number of times.
 */
public class TaskController extends AnchorPane {
	private static final Logger LOG = LoggerFactory.getLogger(MainApp.class);

	private static final String TASK_VIEW_FXML = "/fxml/TaskView.fxml";
	private final URL taskViewFxmlUrl = getClass().getResource(TASK_VIEW_FXML);
	
	private static final String START_DATETIME_TEXT = "S: %s @ %s";
	private static final String END_DATETIME_TEXT = "E: %s @ %s";
	
	/* These are components in this section of the UI, and they will be
	 * injected into by FXML automatically.
	 * 
	 * DO NOT CREATE NEW INSTANCES OF THESE! (unless you know what you are doing)
	 */
	@FXML AnchorPane taskPane;
	@FXML Circle indexCircle;
	@FXML Label indexNumber;
	@FXML Label taskTitle;
	@FXML ImageView doneImage;
	@FXML ImageView pinImage;
	@FXML Separator separator;
	@FXML Label startDateTime;
	@FXML Label endDateTime;
	@FXML Label freeLabel;
	
	// Called after the FXML file specifying this class as fx:controller is loaded
	@FXML
	public void initialize() {
		assert taskPane != null : "fx:id=\"simpleTaskPane\" was not injected";
		assert indexCircle != null : "fx:id=\"indexCircle\" was not injected";
		assert indexNumber != null : "fx:id=\"indexNumber\" was not injected";
		assert taskTitle != null : "fx:id=\"taskTitle\" was not injected";
		assert pinImage != null : "fx:id=\"pinImage\" was not injected";
		assert doneImage != null : "fx:id=\"doneImage\" was not injected";
		assert separator != null : "fx:id=\"separator\" was not injected";
		assert startDateTime != null : "fx:id=\"startDateTime\" was not injected";
		assert endDateTime != null : "fx:id=\"endDateTime\" was not injected";
		assert freeLabel != null : "fx:id=\"freeLabel\" was not injected";
	}
	
	/**
	 * A constructor for an empty task
	 */
	public TaskController() {
		super();
		UiUtils.loadFxml(this, this, taskViewFxmlUrl);
		showNoTask();
	}
	
	/**
	 * A constructor to create the task view for a task.
	 * 
	 * @param task Task to create the simple task view from.
	 * @param index Display index number of the task.
	 * @param separate True if separator is to be drawn.
	 */
	public TaskController(Task task, int index, boolean separate) {
		super();

		UiUtils.loadFxml(this, this, taskViewFxmlUrl);
		
		showSeparator(separate);
		setTaskTitle(task.getDescription());
		setIndexNumber(index);
		showPin(task.isPinned());
		showDone(task.isDone());
		
		if (task.getStart() == null && task.getEnd() == null) {
			// floating
			setCircleColor(UiOptions.GREEN);
		} else if (task.getStart() != null && task.getEnd() != null) {
			// start && end
			setCircleColor(UiOptions.BLUE);
		} else if (task.getStart() != null) {
			// start only
			setCircleColor(UiOptions.AMBER);
		} else if (task.getEnd() != null) {
			// end only
			setCircleColor(UiOptions.LIGHT_RED);
		} else {
			LOG.error("Invalid task passed to TaskController. UUID: " + 
					task.getTaskId().toString());
			throw new Error("Invalid task!");
		}
		
    if (task.getStartDate() != null && task.getStartTime() != null) {
      String taskStartDate = task.getStartDate().toString(
                      DateTimeFormatters.stdDateFormatter);
      String taskStartTime = task.getStartTime().toString(
      								DateTimeFormatters.time24Formatter);
      setStartDateTime(taskStartDate, taskStartTime);
    } else {
    	setStartDateTime(null, null);
    }

    if (task.getEndDate() != null && task.getEndTime() != null) {
      String taskEndDate = task.getEndDate().toString(
                      DateTimeFormatters.stdDateFormatter);
      String taskEndTime = task.getEndTime().toString(
      								DateTimeFormatters.time24Formatter);
      setEndDateTime(taskEndDate, taskEndTime);
      
      // Check if task is overdue
      boolean isTaskOverdue = isTaskOverdue(task);
      
  		if (isTaskOverdue && !task.isDone()) {
  			setTextColor(UiOptions.WARNING_RED);
  		}
  		
  		if (task.isDone()) {
  			setTextColor(UiOptions.LIGHT_GREY);
  		}
    } else {
    	setEndDateTime(null, null);
    }
	}

	/**
	 * Checks if a task is overdue.
	 * @param task Task to check.
	 * @return True if the task is overdue.
	 */
	private boolean isTaskOverdue(Task task) {
		DateTime currentDateTime = new DateTime();
		int daysBetweenEnd = Days.daysBetween(currentDateTime.toLocalDate(), 
				task.getEndDate()).getDays();
		
		if (daysBetweenEnd < 0) {
			return true;
		}
		
		if (daysBetweenEnd == 0) {
			// Task ends on the same day, check time
			DateTimeComparator timeComparator = DateTimeComparator.getTimeOnlyInstance();
			int timeCompare = timeComparator.compare(currentDateTime, task.getEnd());
			
			/* Task has ended earlier today: current > end */
			if (timeCompare > 0) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Sets the color of all text elements of the task view.
	 * @param color String representing the color to set the text.
	 */
	private void setTextColor(String color) {
		taskTitle.setTextFill(Paint.valueOf(color));
		startDateTime.setTextFill(Paint.valueOf(color));
		endDateTime.setTextFill(Paint.valueOf(color));
	}
	
	/**
	 * Sets all the display elements of the task view to invisible.
	 */
	private void showNoTask() {
		taskTitle.setVisible(false);
		startDateTime.setVisible(false);
		endDateTime.setVisible(false);
		indexNumber.setVisible(false);
		indexCircle.setVisible(false);
		pinImage.setVisible(false);
		doneImage.setVisible(false);
		separator.setVisible(false);
		freeLabel.setVisible(true);
	}
	
	/* Private setters for the task's attributes */
	
	private void setTaskTitle(String title) {
		taskTitle.setText(title);
	}
	
	private void setStartDateTime(String date, String time) {
		if (date == null && time == null) {
			startDateTime.setText("");
		} else {
			startDateTime.setText(String.format(START_DATETIME_TEXT, date, time));
		}
	}
	
	private void setEndDateTime(String date, String time) {
		if (date == null && time == null) {
			endDateTime.setText("");
		} else {
			endDateTime.setText(String.format(END_DATETIME_TEXT, date, time));
		}
	}	
	private void setIndexNumber(int index) {
		indexNumber.setText(Integer.toString(index));
	}
	
	private void setCircleColor(String color) {
		indexCircle.setFill(Paint.valueOf(color));
	}
	
	private void showPin(boolean show) {
		pinImage.setVisible(show);
	}
	
	private void showDone(boolean show) {
		doneImage.setVisible(show);
	}
	
	private void showSeparator(boolean show) {
		separator.setVisible(show);
	}
}
